import base64
import hashlib
from datetime import datetime, timedelta

from captcha.views import CaptchaStore, captcha_image
from django.contrib import auth
from django.contrib.auth import login
from django.shortcuts import redirect
from django.utils.translation import gettext_lazy as _
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
from rest_framework import serializers
from rest_framework.views import APIView
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework_simplejwt.views import TokenObtainPairView

from django.conf import settings

from application import dispatch
from dvadmin.system.models import Users
from dvadmin.utils.json_response import ErrorResponse, DetailResponse
from dvadmin.utils.request_util import save_login_log
from dvadmin.utils.serializers import CustomModelSerializer
from dvadmin.utils.validator import CustomValidationError
from django_redis import get_redis_connection
from conf.env import IS_SINGLE_TOKEN, endpoint, client_id, client_secret, certificate, application_name, org_name,is_sync_user,oidc_field
import logging
from casdoor import CasdoorSDK


logger = logging.getLogger(__name__)

class CaptchaView(APIView):
    authentication_classes = []
    permission_classes = []

    @swagger_auto_schema(
        responses={"200": openapi.Response("获取成功")},
        security=[],
        operation_id="captcha-get",
        operation_description="验证码获取",
    )
    def get(self, request):
        data = {}
        if dispatch.get_system_config_values("base.captcha_state"):
            hashkey = CaptchaStore.generate_key()
            id = CaptchaStore.objects.filter(hashkey=hashkey).first().id
            imgage = captcha_image(request, hashkey)
            # 将图片转换为base64
            image_base = base64.b64encode(imgage.content)
            data = {
                "key": id,
                "image_base": "data:image/png;base64," + image_base.decode("utf-8"),
            }
        return DetailResponse(data=data)


class NewLoginSerializer(TokenObtainPairSerializer):
    """
    登录的序列化器:
    重写djangorestframework-simplejwt的序列化器
    """
    captcha = serializers.CharField(max_length=6)

    class Meta:
        model = Users
        fields = "__all__"
        read_only_fields = ["id"]

    default_error_messages = {
        'no_active_account': _('该账号已被禁用,请联系管理员')
    }

    # 开启验证码验证
    # def validate(self, attrs):
    #     captcha = self.initial_data.get("captcha", None)
    #     if dispatch.get_system_config_values("base.captcha_state"):
    #         if captcha is None:
    #             raise CustomValidationError("验证码不能为空")
    #         self.image_code = CaptchaStore.objects.filter(
    #             id=self.initial_data["captchaKey"]
    #         ).first()
    #
    #
    #         # 先去掉验证码验证
    #         five_minute_ago = datetime.now() - timedelta(hours=0, minutes=5, seconds=0)
    #
    #         if self.image_code and five_minute_ago > self.image_code.expiration:
    #             self.image_code and self.image_code.delete()
    #             raise CustomValidationError("验证码过期")
    #         else:
    #             if self.image_code and (
    #                     self.image_code.response == captcha
    #                     or self.image_code.challenge == captcha
    #             ):
    #                 self.image_code and self.image_code.delete()
    #             else:
    #                 self.image_code and self.image_code.delete()
    #                 raise CustomValidationError("图片验证码错误")

    def validate(self, attrs):
        username = attrs['username']
        password = attrs['password']
        user = Users.objects.filter(username=username).first()

        if not user:
            result = {
                "code": 4000,
                "msg": "账号/密码不正确",
                "data": None
            }
            return result

        if user and not user.is_staff:  # 判断是否允许登录后台
            result = {
                "code": 4000,
                "msg": "您没有权限登录后台",
                "data": None
            }

            return result

        if user and not user.is_active:
            result = {
                "code": 4000,
                "msg": "该账号已被禁用,请联系管理员",
                "data": None
            }
            return result

        if user and user.check_password(password):  # check_password() 对明文进行加密,并验证
            data = super().validate(attrs)
            refresh = self.get_token(self.user)

            data['name'] = self.user.name
            data['userId'] = self.user.id
            data['refresh'] = str(refresh)
            data['access'] = str(refresh.access_token)
            request = self.context.get('request')
            request.user = self.user
            # 记录登录成功日志
            save_login_log(request=request)
            # 缓存用户的jwt token
            if IS_SINGLE_TOKEN:
                redis_conn = get_redis_connection("singletoken")
                k = "lybbn-single-token{}".format(user.id)
                TOKEN_EXPIRE_CONFIG = getattr(settings, 'SIMPLE_JWT', None)
                if TOKEN_EXPIRE_CONFIG:
                    TOKEN_EXPIRE = TOKEN_EXPIRE_CONFIG['ACCESS_TOKEN_LIFETIME']
                    redis_conn.set(k, data['access'], TOKEN_EXPIRE)
            result = {
                "code": 2000,
                "msg": "请求成功",
                "data": data
            }
        else:
            result = {
                "code": 4000,
                "msg": "账号/密码不正确",
                "data": None
            }
        return result


class LoginSerializer(TokenObtainPairSerializer):
    """
    登录的序列化器:
    重写djangorestframework-simplejwt的序列化器
    """

    captcha = serializers.CharField(
        max_length=6, required=False, allow_null=True, allow_blank=True
    )

    class Meta:
        model = Users
        fields = "__all__"
        read_only_fields = ["id"]

    default_error_messages = {"no_active_account": _("账号/密码错误")}

    def validate(self, attrs):
        captcha = self.initial_data.get("captcha", None)
        if dispatch.get_system_config_values("base.captcha_state"):
            if captcha is None:
                raise CustomValidationError("验证码不能为空")
            self.image_code = CaptchaStore.objects.filter(
                id=self.initial_data["captchaKey"]
            ).first()


            # 先去掉验证码验证
            five_minute_ago = datetime.now() - timedelta(hours=0, minutes=5, seconds=0)

            if self.image_code and five_minute_ago > self.image_code.expiration:
                self.image_code and self.image_code.delete()
                raise CustomValidationError("验证码过期")
            else:
                if self.image_code and (
                        self.image_code.response == captcha
                        or self.image_code.challenge == captcha
                ):
                    self.image_code and self.image_code.delete()
                else:
                    self.image_code and self.image_code.delete()
                    raise CustomValidationError("图片验证码错误")


        #
        # data = super().validate(attrs)
        # data["name"] = self.user.name
        # data["userId"] = self.user.id
        # data["avatar"] = self.user.avatar
        # request = self.context.get("request")
        # request.user = self.user
        # # 记录登录日志
        # save_login_log(request=request)
        # return {"code": 2000, "msg": "请求成功", "data": data}
    def validate(self, attrs):
        username = attrs['username']
        password = attrs['password']
        user = Users.objects.filter(username=username).first()

        if not user:
            result = {
                "code": 4000,
                "msg": "账号/密码不正确",
                "data": None
            }
            return result

        # if user and not user.is_staff:  # 判断是否允许登录后台
        #     result = {
        #         "code": 4000,
        #         "msg": "您没有权限登录后台",
        #         "data": None
        #     }

            # return result

        if user and not user.is_active:
            result = {
                "code": 4000,
                "msg": "该账号已被禁用,请联系管理员",
                "data": None
            }
            return result

        if user and user.check_password(password):  # check_password() 对明文进行加密,并验证
            data = super().validate(attrs)
            refresh = self.get_token(self.user)
            data['name'] = self.user.name
            data['userId'] = self.user.id
            data['refresh'] = str(refresh)
            data['access'] = str(refresh.access_token)
            request = self.context.get('request')
            request.user = self.user
            # 记录登录成功日志
            save_login_log(request=request)
            # 缓存用户的jwt token
            if IS_SINGLE_TOKEN:
                redis_conn = get_redis_connection("singletoken")
                k = "lybbn-single-token{}".format(user.id)
                TOKEN_EXPIRE_CONFIG = getattr(settings, 'SIMPLE_JWT', None)
                if TOKEN_EXPIRE_CONFIG:
                    TOKEN_EXPIRE = TOKEN_EXPIRE_CONFIG['ACCESS_TOKEN_LIFETIME']
                    redis_conn.set(k, data['access'], TOKEN_EXPIRE)
            result = {
                "code": 2000,
                "msg": "请求成功",
                "data": data
            }
        else:
            result = {
                "code": 4000,
                "msg": "账号/密码不正确",
                "data": None
            }
        return result



class LoginView(TokenObtainPairView):
    """
    登录接口
    """

    serializer_class = LoginSerializer
    permission_classes = []


class LoginTokenSerializer(TokenObtainPairSerializer):
    """
    登录的序列化器:
    """

    class Meta:
        model = Users
        fields = "__all__"
        read_only_fields = ["id"]

    default_error_messages = {"no_active_account": _("账号/密码不正确")}

    def validate(self, attrs):
        if not getattr(settings, "LOGIN_NO_CAPTCHA_AUTH", False):
            return {"code": 4000, "msg": "该接口暂未开通!", "data": None}
        data = super().validate(attrs)
        data["name"] = self.user.name
        data["userId"] = self.user.id
        return {"code": 2000, "msg": "请求成功", "data": data}


class LoginTokenView(TokenObtainPairView):
    """
    登录获取token接口
    """

    serializer_class = LoginTokenSerializer
    permission_classes = []


class LogoutView(APIView):
    def post(self, request):
        return DetailResponse(msg="注销成功")


class ApiLoginSerializer(CustomModelSerializer):
    """接口文档登录-序列化器"""

    username = serializers.CharField()
    password = serializers.CharField()

    class Meta:
        model = Users
        fields = ["username", "password"]


class ApiLogin(APIView):
    """接口文档的登录接口"""

    serializer_class = ApiLoginSerializer
    authentication_classes = []
    permission_classes = []

    def post(self, request):
        username = request.data.get("username")
        password = request.data.get("password")
        user_obj = auth.authenticate(
            request,
            username=username,
            password=hashlib.md5(password.encode(encoding="UTF-8")).hexdigest(),
        )
        if user_obj:
            login(request, user_obj)
            return redirect("/")
        else:
            return ErrorResponse(msg="账号/密码错误")
class CasdoorView(APIView,TokenObtainPairSerializer):
    class Meta:
        model = Users
        fields = "__all__"
        read_only_fields = ["id"]

    def get(self, request):
        sdk = CasdoorSDK(
            endpoint =endpoint,
            client_id =client_id,
            client_secret = client_secret,
            certificate =certificate,
            org_name = org_name,
            application_name = application_name,
        )
        data = self.request.query_params
        code = data.get('code',None)
        state = data.get('state',None)
        if code and state:
            try:
                access_token = sdk.get_oauth_token(code=code)
                usertoken = sdk.parse_jwt_token(access_token)
                print(usertoken)
                # {'owner': 'built-in', 'name': 'admin', 'createdTime': '2023-02-14T01:53:05Z', 'updatedTime': '', 'id': '13098166-87e4-4bd4-9cee-fc81e431eb02', 'type': 'normal-user', 'password': '', 'passwordSalt': '', 'displayName': 'Admin', 'firstName': '', 'lastName': '', 'avatar': 'https://cdn.casbin.org/img/casbin.svg', 'permanentAvatar': '', 'email': 'admin@example.com', 'emailVerified': False, 'phone': '12345678910', 'location': '', 'address': [], 'affiliation': 'Example Inc.', 'title': '', 'idCardType': '', 'idCard': '', 'homepage': '', 'bio': '', 'region': '', 'language': '', 'gender': '', 'birthday': '', 'education': '', 'score': 2000, 'karma': 0, 'ranking': 1, 'isDefaultAvatar': False, 'isOnline': False, 'isAdmin': True, 'isGlobalAdmin': True, 'isForbidden': False, 'isDeleted': False, 'signupApplication': 'app-built-in', 'hash': '', 'preHash': '', 'createdIp': '127.0.0.1', 'lastSigninTime': '', 'lastSigninIp': '', 'ldap': '', 'properties': {}, 'roles': [], 'permissions': [], 'lastSigninWrongTime': '', 'signinWrongTimes': 0, 'tokenType': 'access-token', 'tag': 'staff', 'scope': 'read', 'iss': 'http://localhost:9000', 'sub': '13098166-87e4-4bd4-9cee-fc81e431eb02', 'aud': ['d3e72095581e15892e52'], 'exp': 1682158923, 'nbf': 1681554123, 'iat': 1681554123, 'jti': 'admin/f7223591-853f-4a97-b761-3c08d46b6025'}
                user = Users.objects.filter(username=usertoken['name']).first()
                if not user :
                    if is_sync_user == False:
                        return ErrorResponse(msg="没有该用户，请排查")
                    else:
                        userdata = {}
                        for i,k in oidc_field.items():
                            userdata[k] = usertoken[i]
                        user = Users.objects.create(**userdata)

                data = {}
                refresh = self.get_token(user)
                data['name'] = user.name
                data['userId'] = user.id
                data['refresh'] = str(refresh)
                data['access'] = str(refresh.access_token)

                # 缓存用户的jwt token
                if IS_SINGLE_TOKEN:
                    redis_conn = get_redis_connection("singletoken")
                    k = "lybbn-single-token{}".format(user.id)
                    TOKEN_EXPIRE_CONFIG = getattr(settings, 'SIMPLE_JWT', None)
                    if TOKEN_EXPIRE_CONFIG:
                        TOKEN_EXPIRE = TOKEN_EXPIRE_CONFIG['ACCESS_TOKEN_LIFETIME']
                        redis_conn.set(k, data['access'], TOKEN_EXPIRE)

                return DetailResponse(data=data,msg='登入成功')
            except Exception as e:
                logger.error(str(e))
                return ErrorResponse(msg="统一认证失败，请联系管理员")

        return ErrorResponse(msg="无效的参数")


